package com.partner.boot.service.impl;

import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.partner.boot.entity.Chat;
import com.partner.boot.entity.User;
import com.partner.boot.service.IChatService;
import com.partner.boot.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.OnOpen;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/*
 * websocket服务
 * */
@ServerEndpoint(value = "/imserver/{uid}")
@Component
public class WebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    /*
    * 记录当前在线连接数
    * */
    public static final Map<String,Session> sessionMap = new ConcurrentHashMap<>();

    @Resource
    IUserService userService;

    @Resource
    IChatService chatService;

    private static IUserService staticUserServices;
    private static IChatService staticChatService;

    // 在页面初始化的时候赋值
    @PostConstruct
    public void setServices() {
        staticUserServices = userService;
        staticChatService = chatService;
    }

    /*
    * 连接建立成功调用的方法
    * */
    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) {
        sessionMap.put(uid,session);
        log.info("有新用户加入，uid={},当前在线人数：{}",uid,sessionMap.size());
        Dict dict = Dict.create().set("nums", sessionMap.size());
        sendAllMessage(JSONUtil.toJsonStr(dict)); // 后台发送信息给所有的客户端
    }

    /*
    * 连接关闭调用方法
    * */
    @OnClose
    public void onClose(Session session,@PathParam("uid") String uid) {
        sessionMap.remove(uid);
        log.info("有一连接关闭，uid={}的用户session,当前在线人数：{}",uid,sessionMap.size());
        Dict dict = Dict.create().set("nums", sessionMap.size());
        sendAllMessage(JSONUtil.toJsonStr(dict)); // 后台发送信息给所有的客户端
    }

    /*
    * 收到客户端信息后调用的方法
    * 后台收到客户端发送过来的信息
    * onMessage是一个信息的中转站
    * 接受 浏览器 socket.send 发送过来的json数据
    * @param message 客户端发送过来的信息
    * */
    @OnMessage
    public void onMessage(String message,Session fromSession, @PathParam("uid") String uid) throws JsonProcessingException {
        log.info("服务端收到用户uid={}的信息：{}",uid,message);
        // 获取信息存储到数据库
        User user = staticUserServices.getOne(new QueryWrapper<User>().eq("uid", uid));
        if (user == null) {
            log.error("获取用户信息失败：uid={}",uid);
        }
        // 根据用户信息存储到信息表中
        assert user != null;
        Chat chat = Chat.builder().uid(user.getUid()).name(user.getName()).sign(user.getSign())
                .context(message).avatar(user.getAvatar()).createTime(LocalDateTime.now()).build();
        // 存储信息到数据库
        staticChatService.save(chat);
        // 转换成json格式发送给所有人
        String jsonStr = new ObjectMapper().writeValueAsString(chat);
        this.sendAllMessage(jsonStr);
        log.info("发送信息：{}",jsonStr);
    }

    @OnError
    public void onError(Session session,Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /*
    * 服务端发送信息给除了自己的其他客户端
    * */
    private void sendMessage(Session fromSession, String message) {
        sessionMap.values().forEach(session -> {
            if (fromSession != session) {
                log.info("服务端给客户端[{}]发送信息{}",session.getId(),message);
                try {
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.error("服务端给客户端发送信息异常",e);
                }
            }
        });
    }


    /*
    * 服务端发送信息给所有用户
    * */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
                log.info("服务端给客户端[{}]发送信息{}",session.getId(),message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务端发送信息给客户端失败",e);
        }
    }
}
